#pragma once
#include <iostream>
#include <vector>
#include "myh/PthreadMutex.hpp"
#include "myh/MyLog.hpp"
#include <string>
#include <queue>
#include <mutex>
template <class T>
class PthPool
{
    struct Pthtidname
    {
        pthread_t _tid;
        std::string _pthname;
    };
    static const size_t defaultnum = 10;
    void HandleRet(const std::string &funname, int _error)
    {
        if (_error)
        {
            lg.defaultprint("funname", _error);
        }
    }
    bool getqempty() const { return _qtask.empty(); }
    static void *Handle(void *args)
    {
        PthPool<T> *th = static_cast<PthPool<T> *>(args);
        std::string name = th->Getname(pthread_self());
        while (true)
        {
            th->_mutex.lock();
            while (th->getqempty())
            {
                th->_cond.wait(th->_mutex.getlock());
            }
            T t = th->pop();
            std::cout << name << "->t:" << t << std::endl;
            th->_mutex.unlock();
        }

        return nullptr;
    }
    T pop()
    {
        T val = _qtask.front();
        _qtask.pop();
        return val;
    }
    std::string Getname(pthread_t tid)
    {
        for (auto &pth : _vpth)
        {
            if (pth._tid == tid)
            {
                return pth._pthname;
            }
        }
        return "None";
    }

public:
    void start()
    {
        for (size_t i = 0; i < _vpth.size(); i++)
        {
            _vpth[i]._pthname = "pthread-" + std::to_string(i);
            int ret = pthread_create(&_vpth[i]._tid, nullptr, Handle, this);
            HandleRet("pthread_create", ret);
        }
    }

    void push(const T &val)
    {
        _mutex.lock();
        _qtask.push(val);
        _cond.signal();
        _mutex.unlock();
    }
    static PthPool<T> *Getinitance(size_t num = defaultnum)
    {
        // while (_this == nullptr)
        // {
        //     Guardlock();
        //     if (_this == nullptr)
        //     {
        //         _this = new PthPool<T>(num);
        //     }
        // }
        //c++11
        static std::once_flag once;
        std::call_once(once, [num]()
                       { _this = new PthPool<T>(num); });
        return _this;
    }
    PthPool(const PthPool<T> &pth) = delete;
    const PthPool<T> &operator=(const PthPool<T> &pth) const = delete;

private:
    PthPool(size_t num)
        : _vpth(num)
    {
    }
    ~PthPool()
    {
    }

    PthMutex _mutex;
    PthCond _cond;
    std::vector<Pthtidname> _vpth;
    std::queue<T> _qtask;
    static PthPool<T> *_this;
};

template <class T>
PthPool<T> *PthPool<T>::_this = nullptr;
